package com.toplabs.unashu.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import com.toplabs.unashu.dto.*;
import com.toplabs.unashu.entity.Blog;
import com.toplabs.unashu.entity.BlogTypes;
import com.toplabs.unashu.entity.Type;
import com.toplabs.unashu.mapper.BlogMapper;
import com.toplabs.unashu.service.BlogService;
import com.toplabs.unashu.service.TypeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author ityanger
 * @since 2020-08-23
 */
@Service
@Slf4j
public class BlogServiceImpl implements BlogService {
    public static final String BLOG_RECOMMEND = "BlogRecommend";
    public static final String BLOG_HOT = "BlogHot";
    public static final String BLOG_DETAILED = "BlogDetailed:";
    public static final String BLOG_TIME_SORT_LIST = "BlogTimeSortList";
    private final StringRedisTemplate stringRedisTemplate;
    private final BlogMapper blogMapper;

    private final TypeService typeService;

    public BlogServiceImpl(BlogMapper blogMapper, TypeService typeService, StringRedisTemplate stringRedisTemplate) {
        this.blogMapper = blogMapper;
        this.typeService = typeService;
        this.stringRedisTemplate = stringRedisTemplate;
    }

    @Override
    public PageDto<BlogQuery> listBlog(SearchBlog searchBlog) {
        searchBlog.setPageNum((searchBlog.getPageNum() - 1) * searchBlog.getPageSize());
        List<BlogQuery> blogs = blogMapper.listBlog(searchBlog);
        int countBlog = blogMapper.countBlog(searchBlog);
        return new PageDto<>(countBlog, blogs);
    }

    @Override
    @Transactional
    public int updateRecCom(RecCom recCom) {
        stringRedisTemplate.delete(BLOG_RECOMMEND);
        return blogMapper.updateRecCom(recCom);
    }

    @Override
    @Transactional
    public int saveBlog(Blog blog) {
        stringRedisTemplate.delete(BLOG_RECOMMEND);
        stringRedisTemplate.delete(BLOG_HOT);
        stringRedisTemplate.delete(BLOG_DETAILED + blog.getId());
        stringRedisTemplate.delete(BLOG_TIME_SORT_LIST);
        stringRedisTemplate.delete("TypeListCount");
        stringRedisTemplate.delete("TypeList");
        Set<String> keys = stringRedisTemplate.keys("BlogArticleByMonth:*");
        Set<String> keys1 = stringRedisTemplate.keys("BlogCount:*");
        if (keys != null) {
            stringRedisTemplate.delete(keys);
        }
        if (keys1 != null) {
            stringRedisTemplate.delete(keys1);
        }
        if (CharSequenceUtil.isEmpty(blog.getTitle())) {
            blog.setTitle(DateUtil.today());
        }
        // 将标签的数据存到blogs_types表中
        List<Type> types = blog.getTypes();
        BlogTypes blogTypes;
        StringBuilder typeIds = new StringBuilder();
        for (Type type : types) {
            if (type.getId() == null) {
                typeService.insertType(type);
            }
            typeIds.append(type.getId()).append(",");
        }
        if (typeIds.length() > 0) {
            typeIds.deleteCharAt(typeIds.length() - 1);
            blog.setTypeIds(typeIds.toString());
            log.debug("typeIds: {}", typeIds);
        }
        blog.setTagNames(CollUtil.join(blog.getTags(), ","));
        log.debug("blog: {}", blog);
        int res = blogMapper.saveBlog(blog);
        for (Type type : types) {
            blogTypes = new BlogTypes(null, type.getId(), null, blog.getId(), null);
            blogMapper.addBlogTags(blogTypes);
        }
        return res;
    }

    @Override
    public Blog getDraft(Long id) {
        Blog blog = null;
        if (null != id) {
            blog = blogMapper.getDraft(id);
        }
        if (blog == null) {
            blog = new Blog();
            blog.setId(IdUtil.getSnowflake(1, 1).nextId());
            blog.setPublished("public");
            blog.setContent("");
            blog.setFlag("");
            blog.setTypeIds("");
            blog.setDescription("");
            blog.setFirstPicture("https://th.wallhaven.cc/small/lm/lmxmxy.jpg");
            blog.setViews(0);
            blog.setTitle(DateUtil.today());
        } else {
            String tagNames = blog.getTagNames();
            if (!CharSequenceUtil.isEmpty(tagNames)) {
                List<String> tags = Arrays.asList(tagNames.split(","));
                blog.setTags(tags);
            }
        }
        return blog;
    }

    @Override
    @Transactional
    public int deleteBlog(Long id) {
        stringRedisTemplate.delete(BLOG_RECOMMEND);
        stringRedisTemplate.delete(BLOG_HOT);
        stringRedisTemplate.delete(BLOG_DETAILED + id);
        stringRedisTemplate.delete(BLOG_TIME_SORT_LIST);
        stringRedisTemplate.delete("TypeListCount");
        Set<String> keys = stringRedisTemplate.keys("BlogArticleByMonth:*");
        Set<String> keys1 = stringRedisTemplate.keys("BlogCount:*");
        if (keys != null) {
            stringRedisTemplate.delete(keys);
        }
        if (keys1 != null) {
            stringRedisTemplate.delete(keys1);
        }
        blogMapper.deleteBlogType(id);
        return blogMapper.deleteBlog(id);
    }

    @Override
    public int countBlog(SearchBlog searchBlog) {
        String s = stringRedisTemplate.opsForValue().get("BlogCount:" + searchBlog.toString());
        if (!CharSequenceUtil.isEmpty(s)) {
            return Integer.parseInt(s);
        }
        int i = blogMapper.countBlog(searchBlog);
        stringRedisTemplate.opsForValue().set("BlogCount:" + searchBlog, String.valueOf(i), 1, TimeUnit.HOURS);
        return i;
    }

    @Override
    public PageDto<PageBlog> getPageBlog(BlogPageable blogPageable) {
        blogPageable.setPageNum((blogPageable.getPageNum() - 1) * blogPageable.getPageSize());
        List<PageBlog> blogs = blogMapper.getPageBlog(blogPageable);
        int countBlog = blogMapper.getPageBlogTotal(blogPageable);
        return new PageDto<>(countBlog, blogs);
    }

    @Override
    public List<RecommendHotBlog> getHotBlog() {
        String s = stringRedisTemplate.opsForValue().get(BLOG_HOT);
        if (!CharSequenceUtil.isEmpty(s)) {
            return JSONUtil.toList(JSONUtil.parseArray(s), RecommendHotBlog.class);
        }
        List<RecommendHotBlog> hotBlog = blogMapper.getHotBlog();
        stringRedisTemplate.opsForValue().set(BLOG_HOT, JSONUtil.toJsonStr(hotBlog));
        return hotBlog;
    }

    @Override
    public List<RecommendHotBlog> getRecommendBlog() {
        String s = stringRedisTemplate.opsForValue().get(BLOG_RECOMMEND);
        if (!CharSequenceUtil.isEmpty(s)) {
            return JSONUtil.toList(JSONUtil.parseArray(s), RecommendHotBlog.class);
        }
        List<RecommendHotBlog> recommendBlog = blogMapper.getRecommendBlog();
        stringRedisTemplate.opsForValue().set(BLOG_RECOMMEND, JSONUtil.toJsonStr(recommendBlog));
        return recommendBlog;
    }

    @Override
    public DetailedBlog getDetailedBlog(Long id) {
        DetailedBlog blog = blogMapper.getDetailedBlog(id);
        String s = stringRedisTemplate.opsForValue().get(BLOG_DETAILED + id);
        if (!CharSequenceUtil.isEmpty(s)) {
            return JSONUtil.toBean(s, DetailedBlog.class);
        }
        String tagNames = blog.getTagNames();
        if (!CharSequenceUtil.isEmpty(tagNames)) {
            List<String> tags = Arrays.asList(tagNames.split(","));
            blog.setTags(tags);
        }
        String render = blog.getRender();
        render = render.replaceAll("<(h[1-6])><a id=(\"\\w+\")></a>", "<$1 id=$2>");
        blog.setRender(render);
        log.info("blog detail:{}", blog);
        stringRedisTemplate.opsForValue().set(BLOG_DETAILED + id, JSONUtil.toJsonStr(blog));
        return blog;
    }

    @Override
    public List<String> getBlogTimeSortList() {
        String s = stringRedisTemplate.opsForValue().get(BLOG_TIME_SORT_LIST);
        if (!CharSequenceUtil.isEmpty(s)) {
            return JSONUtil.toList(JSONUtil.parseArray(s), String.class);
        }
        List<String> groupYearMonth = blogMapper.getGroupYearMonth();
        stringRedisTemplate.opsForValue().set(BLOG_TIME_SORT_LIST, JSONUtil.toJsonStr(groupYearMonth));
        return groupYearMonth;
    }

    @Override
    public List<ArchivesBlog> getArticleByMonth(String monthDate) {
        String s = stringRedisTemplate.opsForValue().get("BlogArticleByMonth:" + monthDate);
        if (!CharSequenceUtil.isEmpty(s)) {
            return JSONUtil.toList(JSONUtil.parseArray(s), ArchivesBlog.class);
        }
        List<ArchivesBlog> articleByMonth = blogMapper.getArticleByMonth(monthDate);
        stringRedisTemplate.opsForValue().set("BlogArticleByMonth:" + monthDate, JSONUtil.toJsonStr(articleByMonth));
        return articleByMonth;
    }

    @Override
    public void updateViews(Long id) {
        blogMapper.updateViews(id);
    }

}
